/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bugman.dao.impl;

import com.bugman.dao.Dao;
import com.bugman.entity.Bug;
import com.bugman.entity.Comment;
import com.bugman.entity.Importance;
import com.bugman.entity.Project;
import com.bugman.entity.Role;
import com.bugman.entity.Status;
import com.bugman.entity.User;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.log4j.Logger;

/**
 *
 * @author komarek
 */
@Stateless
public class JpaDaoBean implements Dao {

    @PersistenceContext
    EntityManager em;
    private Logger logger;

    public JpaDaoBean() {
        logger = Logger.getLogger(this.getClass());
        logger.info("Vytvarim DAO bean " + this.getClass().getSimpleName());
    }

    // CRUD methods
    public <T> void persist(T entity) {
        em.persist(entity);
    }

    public <T> void merge(T entity) {
        em.merge(entity);
    }

    public <T> void remove(T entity) {
        em.remove(entity);
    }

    public <T> void refresh(T entity) {
        em.refresh(entity);
    }

    public void flush() {
        em.flush();
    }

    public <T> T load(Class<T> entityClass, Object key) {
        return em.find(entityClass, key);
    }

    // Role
    public Role getRoleById(Byte roleId) {
        return em.find(Role.class, roleId);
    }


    // Status
    public Status getStatusById(Byte statusId) {
        return em.find(Status.class, statusId);
    }

    public List<Status> getAllStatus() {
        try {
            Query query = em.createNamedQuery(Status.findAll);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    //Importance
    public Importance getImportanceById(Byte importanceId) {
        return em.find(Importance.class, importanceId);
    }

    public List<Importance> getAllImportance() {
        try {
            Query query = em.createNamedQuery(Importance.findAll);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    /**
     * Tato metoda kontroluje, zdali uzivatelske jmeno jiz neexistuje v databazi
     * @param username
     * @return
     */
    public User getUser(String username) {
        try {
            Query query = em.createNamedQuery(User.findByUsername);
            query.setParameter("username", username);
            return (User) query.getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    public User getUser(Integer userId) {
        try {
            return em.find(User.class, userId);
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<User> getUsers(Byte roleId) {
        try {
            Query query = em.createNamedQuery(User.findByRoleId);
            query.setParameter("roleId", roleId);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<User> getUsers(List<Integer> userIds) {
        List<User> users = new ArrayList<User>();
        
        try {
            for (Integer id : userIds) {
                users.add(getUser(id));
            }
            return users;
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<User> getAllUsers() {
        try {
            Query query = em.createNamedQuery(User.findAll);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    // Project
    public List<Project> getAllProjects() {
        try {
            Query query = em.createNamedQuery(Project.findAll);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public Project getProject(Integer projectId) {
        return em.find(Project.class, projectId);
    }

    public Project getProject(String projectName) {
        try {
            Query query = em.createNamedQuery(Project.findByProjectName);
            query.setParameter("projectName", projectName);
            return (Project) query.getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<Project> getOwnedProjects(User developer) {
        try {
            Query query = em.createQuery("SELECT p FROM Project p WHERE p.creator = :developer " +
                    "ORDER BY p.name ASC");
            query.setParameter("developer", developer);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<Project> getNotOwnedProjects(User developer) {
        try {
            Query query = em.createQuery("SELECT p FROM Project p WHERE p.creator <> :developer " +
                    "ORDER BY p.name ASC");
            query.setParameter("developer", developer);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<Project> getMostActiveProjects(Integer count) {
        try {
            Query query = em.createQuery("SELECT DISTINCT(p) FROM Project p LEFT JOIN FETCH" +
                    "p.bugs b ORDER BY b.creationTime DESC");
            query.setMaxResults(count);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    // Bug
    public List<Bug> getAllBugs() {
        try {
            Query query = em.createNamedQuery(Bug.findAll);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<Bug> getBugs(Status status, Importance importance, Integer count) {
        try {
            Map parameters = new HashMap();
            StringBuffer queryBuf = new StringBuffer("SELECT b FROM Bug b");
            boolean firstClause = true;

            if (status != null) {
                  queryBuf.append(firstClause ? " WHERE " : " AND ");
                  queryBuf.append("b.status = :status");
                  parameters.put("status", status);
                  firstClause = false;
            }
            if (importance != null) {
                  queryBuf.append(firstClause ? " WHERE " : " AND ");
                  queryBuf.append("b.importance = :importance");
                  parameters.put("importance", importance);
                  firstClause = false;
            }

            queryBuf.append(" ORDER BY b.creationTime DESC");
            String hqlQuery = queryBuf.toString();

            Query query = em.createQuery(hqlQuery);
            Iterator iter = parameters.keySet().iterator();
            while (iter.hasNext()) {
                String name = (String) iter.next();
                Object value = parameters.get(name);
                query.setParameter(name,value);
            }


            query.setMaxResults(count);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }



    public List<Bug> getLatestBugs(Integer count) {
        try {
            Query query = em.createQuery("SELECT b FROM Bug b ORDER BY b.creationTime DESC");
            query.setMaxResults(count);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<Bug> getLatestProjectBugs(Project project, Integer count) {
        try {
            Query query = em.createQuery("SELECT b FROM Bug b WHERE b.project = :project ORDER BY b.creationTime DESC");
            query.setParameter("project", project);
            query.setMaxResults(count);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public Integer getBugsCount(Project project) {
        try {
            Query query = em.createQuery("SELECT count(b) FROM Bug b WHERE b.project = :project");
            query.setParameter("project", project);
            return ((Long) query.getSingleResult()).intValue();
        } catch (NoResultException e) {
            return 0;
        }
    }

    public Integer getBugsCount() {
        try {
            Query query = em.createQuery("SELECT count(b) FROM Bug b");
            return ((Long) query.getSingleResult()).intValue();
        } catch (NoResultException e) {
            return 0;
        }
    }

    // Comment
    public boolean isCommentLast(Comment comment) {
        Query query = em.createQuery("SELECT c FROM Comment c WHERE c.bug = :bug AND c.creationTime > :ctime");
        query.setParameter("bug", comment.getBug());
        query.setParameter("ctime", comment.getCreationTime());
        try {
            query.getResultList();
            return false;
        } catch (NoResultException e) {
            return true;
        }
    }

    public List<Comment> getLastComments(Integer count) {
        try {
            Query query = em.createQuery("SELECT c FROM Comment c ORDER BY c.creationTime DESC");
            query.setMaxResults(count);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<Comment> getLastComments(Bug bug, Integer count) {
        try {
            Query query = em.createQuery("SELECT c FROM Comment c WHERE c.bug = :bug ORDER BY c.creationTime DESC");
            query.setParameter("bug", bug);
            query.setMaxResults(count);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public List<Comment> getComments(Bug bug) {
        try {
            Query query = em.createNamedQuery(Comment.findByBug);
            query.setParameter("bug", bug);
            return query.getResultList();
        } catch (NoResultException e) {
            return null;
        }
    }

    public Integer getCommentsCount(Bug bug) {
        try {
            Query query = em.createQuery("SELECT count(c) FROM Comment c WHERE c.bug = :bug");
            query.setParameter("bug", bug);
            return ((Long) query.getSingleResult()).intValue();
        } catch (NoResultException e) {
            return 0;
        }
    }
}
